using System;
using ValidationFramework.Reflection;
using ValidationFramework.Configuration.Reflection;

namespace ValidationFramework.Specifications
{
	/// <summary>
	/// Specifies that a <see cref="RangeRule{T}"/>, that will check the range of a <see cref="byte"/>, should be applied to the program element.
	/// </summary>
	/// <seealso cref="RangeRule{T}"/>
	/// <example>
	/// <code source="Examples\ExampleLibraryCSharp\Specifications\RangeSpecifications\RangeByteRuleAttributeExample.cs" lang="cs"/>
	/// <code source="Examples\ExampleLibraryVB\Specifications\RangeSpecifications\RangeByteRuleAttributeExample.vb" lang="vbnet"/>
	/// </example>
#if (!SILVERLIGHT)
	[Serializable]
#endif
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
	public class IsInRangeAttribute : RuleAttribute
	{

		// --- Constructors

		/// <summary>
		/// Instantiate a new instance of the <see cref="RangeRuleAttribute"/> class.
		/// </summary>
		/// <param name="minimum">The minimum value.</param>
        /// <param name="maximum">The maximum value.</param>
        /// <exception cref="ArgumentNullException"><paramref name="minimum"/> is a null reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="minimum"/> is <see cref="string.Empty"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="maximum"/> is a null reference.</exception>
        /// <exception cref="ArgumentException"><paramref name="maximum"/> is <see cref="string.Empty"/>.</exception>
		public IsInRangeAttribute(object minimum, object maximum)
        {
            Guard.ArgumentNotNull(minimum, "minimum");
			Guard.ArgumentNotNull(maximum, "maximum");
            Minimum = minimum;
            Maximum = maximum;			
			EqualsMinimumIsValid = true;
			EqualsMaximumIsValid = true;
        }


		// --- Properties

		/// <summary>
		/// Get or sets a value indicating if the minimum value is valid.
		/// </summary>
		/// <seealso cref="RangeSpecification.EqualsMinimumIsValid"/>
		public bool EqualsMinimumIsValid
		{
			get;
			set;
		}

		/// <summary>
		/// Get or sets a value indicating if the maximum value is valid.
		/// </summary>
		/// <seealso cref="RangeSpecification.EqualsMaximumIsValid"/>
		public bool EqualsMaximumIsValid
		{
			get;
			set;
		}

		/// <summary>
		/// Gets the minimum value.
		/// </summary>
		/// <seealso cref="RangeSpecification.Minimum"/>
		public object Minimum
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the maximum value.
		/// </summary>
		/// <seealso cref="RangeSpecification.Maximum"/>
		public object Maximum
		{
			get;
			private set;
		}


        // --- Methods

		public override ISpecification CreateSpecification(ICachedReflectionInfo descriptor)
		{
            var typeParam = Type.GetTypeFromHandle(descriptor.MemberTypeHandle);
            var SpecificationType = typeof(IsInRangeSpec<>);
            var Specification = (IIsInRangeSpecification)SpecificationType.CreateGenericInstance(typeParam, new object[] { Minimum, Maximum });

            Specification.EqualsMinimumIsValid = EqualsMinimumIsValid;
            Specification.EqualsMaximumIsValid = EqualsMaximumIsValid;
            return Specification;
		}

	}
}